/*
涂鸦工具 第二版
依赖于:html5 canvas,jQuery,font-awesome
需要Internet Explorer 9+, Firefox, Opera, Chrome 以及 Safari 
作者:徐东强 2018-09-11 xdq025@sina.com

1.默认支持自适应父元素.
    a.在自适应父元素时，父元素必须有大小设置
    b.在自适应父元素时，页面大小变化，将引起画布重绘
2.默认是缩放状态
    a.缩放状态下，不支持按比例缩放，只会居中缩放
3.仅支持从元素直接创建画布
4.


Api调整：
1.height从方法改为属性，添加set方法，由set改变属性.get获取属性
2.不再支持强制运行，加载后立即运行,并设置默认大小。
3.不允许外部直接访问任何属性，只能通过get/set访问。
4.options内所有的调用方式都是call(options).因此，每个方法默认访问this就是options对象
5.不再将format等可能造成污染的依赖函数直接对原生函数进行扩展
*/



//依赖函数
(function (global) {

    global.myCanvasFormat = function (text, args) {
        /// <summary>格式化字符串</summary>
        if (myCanvasFormat.isNum.test(text)) {
            args = Array.prototype.slice.call(arguments, 1);
            for (var i = 0;i < args.length;i++) {
                var it = args[i];
                if (it !== undefined && it !== null) {
                    var reg = new RegExp("({)" + i + "(})", "g");
                    text = text.replace(reg, it);
                }
            }
        } else if (myCanvasFormat.isProperty.test(text)) {
            for (var key in args) {
                var kt = args[key];
                if (kt != undefined && typeof (kt) != 'object') {
                    var reg = new RegExp("({" + key + "})", "g");
                    text = text.replace(reg, kt);
                }
            }
            //删除未替换的占位符。
            //已考虑:
            //vue {{express}}
            //angular {{express}}
            var mc = text.match(myCanvasFormat.regNullProperty);
            for (var i = 0;i < mc.length;i++) {
                var it = mc[i], key = it.substring(1).match(myCanvasFormat.getPropertyKey)[0];
                var reg = new RegExp("({" + key + "})", "g");
                text = text.replace(reg, "");
            }
        }
        return text;
    };
    myCanvasFormat.regNullProperty = /(?:[^\{])(\{\w+\})/ig;
    myCanvasFormat.isNum = /\{\d+\}/;
    myCanvasFormat.isProperty = /\{\w+\}/;
    myCanvasFormat.getPropertyKey = /\w+/;


    global.myCanvasLog = function (msg) {
        if (top.console == null || top.console.log == null || !$.isFunction(top.console.log)) {
            return;
        }
        else {
            top.console.log(msg);
        }
    };


    global.myCanvasMaxZIndex = function (win) {
        var maxZ = Math.max.apply(null,
        $.map(win.$('body *'), function (e, n) {
            if (win.$(e).css('position') != 'static')
                return parseInt(win.$(e).css('z-index')) || -1;
        }));
        return maxZ;
    };

    global.myCanvasFormatUrl = function (url, win) {
        if (!/^http:/ig.test(url)) {
            if (/^\.\./.test(url) || /^\w/.test(url)) {
                var pathArray = global.location.href.split('/')
                , file = pathArray.pop()
                , urlArray = url.replace(/[\\|\/]/, '/').split('/')
                , urlFile = urlArray.pop()
                , newPathArray = []
                , newUrlArrary = Array.prototype.slice.call(urlArray, 0);
                for (var i = 0;i < pathArray.length;i++) {
                    var it = pathArray[i];
                    if (!!it) newPathArray.push(it);
                }
                for (var i = 0;i < urlArray.length;i++) {
                    var it = urlArray[i];
                    if (!!it) {
                        switch (it) {
                            case ".":
                                newUrlArrary.splice(0, 1);
                                break;
                            case "..":
                                newUrlArrary.splice(0, 1);
                                newPathArray.pop();
                                break;
                            case "":
                                newUrlArrary.splice(0, 1);
                                continue;
                            default:
                                switch (typeof (it)) {
                                    case "string":
                                        var arr = newPathArray.concat(newUrlArrary);
                                        return [arr.join('/'), '/', urlFile].join("").replace("http:", "http:/");
                                }
                                break;
                        }
                    }
                }
                return ('/' + newPathArray.join('/'));
            }
        }
        return url;
    };
})(window);

//组件基类
(function ($, global) {
    function readOptionsFromHTML($t) {
        if ($.meta) {
            return $t.meta();
        }
        else {
            var dd = $t.data(), r = {};
            for (var i in dd) {
                var v = dd[i];
                if (/[a-z]{1}\w+/.test(i) && /(string|number|object)/.test(typeof (v))) {
                    r[i] = v;
                }
            }
            return r;
        }
    };

    //呈现器.仅用于初始化
    function render(type, $t, options, a2, a3, a4, a5) {
        var df1 = _deepCopy($.fn[type].defaults)
        , df2 = _deepCopy(readOptionsFromHTML($t))
        , df3 = _deepCopy($.jQ_Componet.defaults)
        , op = _deepCopy(options);
        var options1 = $.extend(true, df3, df1, df2, op);
        if (!!$t.get(0)[type]) {
            return global.myCanvasLog($.jQ_Componet.lang.tips.canvasHasInited);
        }
        options1._.original.$ele = $t;
        //element.model

        $t.get(0)[type] = options1;
        options1["_call"].call(options1, "render", a2, a3, a4, a5);
    };

    $.jQ_Componet = function () {
        var
            type = Array.prototype.shift.call(arguments)
            , a1 = Array.prototype.shift.call(arguments)
            , a2 = Array.prototype.shift.call(arguments)
            , a3 = Array.prototype.shift.call(arguments)
            , a4 = Array.prototype.shift.call(arguments)
            , a5 = Array.prototype.shift.call(arguments)
            , ret = null
            , that = this;

        this.each(function () {
            var $t = $(this);
            if (typeof (a1) === "object") {
                render.call(that, type, $t, a1, a2, a3, a4);
            }
            else if (a1 === undefined) {
                render.call(that, type, $t, {});
            }
            else if (a1 === "render") {
                render.call(that, type, $t, a2 || {}, a3, a4, a5);
            }
            else {
                var options = this[type];
                ret = options["_call"].call(options, a1, a2, a3, a4);
            }
        });
        return (ret === undefined || ret === null) ? this : ret;
    };

    $.jQ_Componet.lang = {
        tips: {
            componentHasInited: "组件在之前初始化过/Components were initialized before!"
            , noMeta: "没有引入jQuery.meta.js/You dont import jQuery.meta.js!"
             , methodNull: "方法名为空，请传入正确的参数/The name of the method is empty. Please pass in the correct parameters!"
        }
    };

    $.jQ_Componet.defaults = {
        _call: function (methodName, a1, a2, a3, a4) {
            if (methodName == null || methodName == undefined || methodName.length < 2) {
                return global.myCanvasLog($.jQ_Componet.lang.tips.methodNull);
            }
            var type = [methodName.substring(0, 1).toUpperCase()
                , methodName.substring(1)
            ].join("");
            if (this.methods._trigger.call(this, ["before", type].join(""), a1, a2, a3, a4) === false)
                return;
            var ret = this.methods[methodName].call(this, a1, a2, a3, a4);
            this.methods._trigger.call(this, ["after", type].join(""), a1, a2, a3, a4);
            return ret;
        }
        //调试模式
        , isDebugger: false
        , methods: {
            render: null
        }
        , props: {}
        ,
        events: {}
        ,
        _: {}
    };

    function _deepCopy(obj) {
        if (obj === null)
            return null;
        var deep = Array.prototype.slice.call(arguments, 1, 2).pop() || 1;
        if (deep > 10) {
            return obj;
        }
        switch (typeof obj) {
            case "object":
                var newobj;
                if (obj instanceof Window)
                    return obj;
                else if (obj instanceof Date)
                    return new Date(obj);
                else if (obj instanceof Array)
                    newobj = [];
                else
                    newobj = {};
                for (var i in obj) {
                    var v = obj[i];
                    newobj[i] = _deepCopy(v, deep + 1);
                }
                return newobj;
            case "function":
                return obj;
            default:
                if (window["JSON"]) {
                    return window["JSON"].parse(window["JSON"].stringify(obj));
                }
                else {
                    switch (typeof obj) {
                        case "number":
                            return parseFloat(obj);
                        case "undefine":
                            return undefined;
                        default:
                        case "string":
                            return obj.toString();
                    }
                }
        }
    };
    $.deepCopy = _deepCopy;
})(jQuery, window);

//画布组件
(function ($, global) {
    function myCanvas() {
        /// <summary>我的画布</summary>
        var ag = Array.prototype.slice.call(arguments);
        ag.splice(0, 0, myCanvas.type);
        return $.jQ_Componet.apply(this, ag);
    };

    //指定组件类型，让组件将数据存放在此数据中
    myCanvas.type = "myCanvas";


    //自定义元素数据
    function MyEleData() {
        this.$ele = null;
        //容器大小
        this.size = new Object();
        this.size.height = 0;
        this.size.width = 0;
        return this;
    };

    //自定义块区数据
    function MyAreaData() {
        this.wrapper = new MyEleData();
        this.bg = new MyEleData();
        this.canvas = new MyEleData();
        this.tools = new MyEleData();
        return this;
    }

    myCanvas.createDefault = function () {
        return JSON.parse(JSON.stringify(myCanvas.defaults));
    };

    myCanvas.defaults = {
        //方法
        methods: {
            _trigger: function (eventType) {
                if (!this._ || !this.props)
                    return;
                var arg = Array.prototype.slice.call(arguments, 1);
                return this._.original.$ele.triggerHandler(eventType, arg);
            }
            ,
            //获取属性值
            get: function (propName) {
                var retValue = this.props[propName];
                if (retValue === undefined && myCanvas.defaults.isDebugger) {
                    global.myCanvasLog([myCanvas.lang.tips.noProperty, "[", propName, "]"].join(""));
                }
                return retValue
            }
            ,
            //修改属性值
            set: function (propName, propValue) {
                if (this.methods._trigger.call(this, "beforeChangeProperty", propName, propValue) === false)
                    return;
                this.props[propName] = propValue;
                this.methods._trigger.call(this, "afterChangeProperty", propName, propValue);
            }
            ,
            //获取当前画布的2d模式
            getCanvas: function () {
                if (!!this._.maxer.canvas.$ele && this._.maxer.canvas.$ele.length > 0) {
                    return this._.maxer.canvas.$ele.get(0).getContext("2d");
                }
                else {
                    return null;
                }
            }
            ,
            //获取画布数据
            getData: function () {
                var rt = this.methods.get.call(this, "value");
                if (rt === null)
                    rt = "";
                return rt;
            },
            //设置画布数据
            setData: function (buffer) {
                this.methods.set.call(this, "value", buffer);
            },
            //只读
            readonly: function (isTrue) {
                this.props.readonly = isTrue;
                Tools.readonly.call(this, isTrue);
            },
            //绑定画布的事件
            bindEvents: function (isMinMode) {
                if (isMinMode) {
                    var er = this._.miner;
                    er.canvas.$ele
                    .off("click", myCanvas._Click_Miner)
                    .off("tap", myCanvas._Click_Miner)
                    .on("click", myCanvas._Click_Miner)
                    .on("tap", myCanvas._Click_Miner);
                    $(window)
                        .off("resize", myCanvas._SizeChanged)
                        .on("resize", myCanvas._SizeChanged);
                    if (this._.original.$ele.is("img")) {
                        var el = this._.original.$ele[0];
                        el.onload = function () {
                            var t = this[myCanvas.type];
                            t.methods._trigger.call(t, "afterLoad");
                        }
                        if (el.complete) {
                            this.methods._trigger.call(this, "afterLoad");
                        };
                    }

                    this._.original.$ele
                    .off("afterChangeProperty", myCanvas._PropertyChange)
                    .on("afterChangeProperty", myCanvas._PropertyChange);
                }
                else {

                    $(document)
                        .off("keydown", myCanvas._KeydownMaxer)
                        .on("keydown", myCanvas._KeydownMaxer);
                }
            }
            ,
            //初始化大小
            initSize: function (isMinMode) {
                var self = this, p = this.props;
                if (isMinMode) {
                    var er = this._.miner;
                    if (this.props.isAutoSizeMode) {
                        er.canvas.$ele.hide();
                        //er.bg.$ele.hide();
                        p.width = er.bg.$ele.width();
                        p.height = er.bg.$ele.height();
                        var pe = er.wrapper.$ele[0];
                        while (p.height <= 0 && pe != document && pe != window && pe != null) {
                            p.height = $(pe).height();
                            pe = pe.parentElement;
                        }
                        if (p.height == 0) {
                            var that = this, el = that._.original.$ele;
                            el.on("afterLoad", function () {
                                er.wrapper.$ele.css({
                                    height: el.height()
                                    , width: el.width()
                                })
                                that.methods.resetSize.call(that, true);
                            });
                        };
                        er.canvas.$ele.show();
                        //er.bg.$ele.show();
                    }
                    else {
                        if (p.height == 0 && p.width == 0) {
                            p.height = er.$ele.height();
                            p.width = er.$ele.width();
                        }
                    }
                }
                else {
                    myCanvas._setScaleSize.call(this);
                }
            }
            ,
            //重设大小
            resetSize: function (isMinMode) {
                var self = this, p = self.props, $bg = self._.miner.bg.$ele, bg = $bg.get(0);
                if (isMinMode === undefined) {
                    this.methods.resetSize.call(this, true);
                    this.methods.resetSize.call(this, false);
                }
                else if (isMinMode) {
                    if (bg.tagName == "IMG" && !!$bg.attr("src") && p.isAutoSizeMode) {
                        if (bg.complete == false) {
                            $bg.one("load", function () {
                                self.methods.resetSize.call(self, isMinMode);
                            });
                            return;
                        }
                    }
                    this.methods.initSize.call(this, true);
                    var er = this._.miner;
                    er.canvas.$ele.width(p.width);
                    er.canvas.$ele.height(p.height);
                    er.bg.$ele.width(p.width);
                    er.bg.$ele.height(p.height);
                }
                else {
                    this.methods.initSize.call(this, false);

                }
            }
            ,
            //绘制器: 显示总的画布
            render: function (isMinMode) {

                if (isMinMode === undefined)
                    isMinMode = true;

                this.methods.rendWrapper.call(this, isMinMode);
                this.methods.rendBackground.call(this, isMinMode);
                this.methods.rendCanvas.call(this, isMinMode);
                this.methods.rendTools.call(this, isMinMode);
                this.methods.bindEvents.call(this, isMinMode);
                //计算大小，必须在渲染完元素之后
                this.methods.resetSize.call(this, isMinMode);

            }
            ,
            //绘制画布
            rendCanvas: function (isMinMode) {
                if (isMinMode) {
                    var er = this._.miner, cvs = er.canvas;
                    if (cvs.$ele == null) {
                        cvs.$ele = $("<img></img>")
                        .addClass("miner-canvas")
                        .addClass("my-canvas");
                        er.wrapper.$ele.append(cvs.$ele);
                        cvs.$ele.get(0)[myCanvas.type] = this;
                        cvs.$ele.attr("alt", myCanvas.lang.tips.clickToPopMode);
                    }
                }
                else {
                    var er = this._.maxer, cvs = er.canvas;
                    if (cvs.$ele == null) {
                        cvs.$ele = $("<canvas></canvas>")
                            .addClass("maxer-canvas")
                            .addClass("my-canvas");
                        er.wrapper.$ele.append(cvs.$ele);
                        cvs.$ele.get(0)[myCanvas.type] = this;
                    }
                }
            }
            ,
            //绘制背景
            rendBackground: function (isMinMode) {
                if (isMinMode) {
                    var bg = this._.miner.bg, ori = this._.original, self = this;
                    if (bg.$ele == null) {
                        if (ori.$ele.attr("readonly")) {
                            this.props.readonly = true;
                        }
                        bg.$ele = ori.$ele;
                        bg.size.width = bg.$ele.width();
                        bg.size.height = bg.$ele.height();
                    }
                }
                else {
                    var er = this._.maxer, bg = er.bg;
                    if (bg.$ele == null) {
                        bg.$ele = this._.miner.bg.$ele.clone()
                        .addClass("maxer-background")
                        .removeClass("myCanvas");
                        var href = bg.$ele.attr("src")
                        , newHref = !!href ? global.myCanvasFormatUrl(href, this.win) : href;
                        bg.$ele.attr("src", newHref);
                        er.wrapper.$ele.append(bg.$ele);
                    }

                }
            }
            ,
            //绘制外围
            rendWrapper: function (isMinMode) {
                if (isMinMode) {
                    var er = this._.miner, wp = er.wrapper;
                    if (wp.$ele == null) {
                        var el = $("<div></div>")
                        .addClass("miner-wrapper")
                        .addClass("canvas-container");
                        var $ori = this._.original.$ele;
                        $ori.wrap(el);
                        wp.$ele = $ori.parent();
                    }
                    if (this.props.height != 0 && this.props.width != 0) {
                        wp.$ele.css({
                            width: this.props.width
                            , height: this.props.height
                            , boxShadow: "0px 0px 5px #666"
                        });
                    }
                }
                else {
                    var er = this._.maxer, wp = er.wrapper, miner = this._.miner, self = this;
                    if (wp.$ele == null) {
                        var win = global;
                        if (this.props.isPopupToTop) {
                            while (win !== win.parent && win.parent.jQuery) {
                                this.win = win = win.parent;
                                this.jq = win.jQuery;
                            }
                            if (this.jq("#jQuery-canvas-css").length == 0) {
                                var url = false, url2 = false;
                                $("link").each(function () {
                                    var $t = $(this), href = $t.attr("href");
                                    if (/jQuery.canvas2/ig.test(href)) {
                                        url = global.myCanvasFormatUrl(href, this.win);
                                        return false;
                                    }
                                });
                                if (!!url) {
                                    var $style = this.jq(global.myCanvasFormat("<link href='{0}' rel='stylesheet'/>", url));
                                    $style.attr("id", "jQuery-canvas-css");
                                    this.jq("body").append($style);
                                }
                            }
                        }
                        wp.$ele = this.jq("<div></div>")
                        .addClass("canvas-container")
                        .addClass("maxer-wrapper")
                        .css($.fn.myCanvas.styles.popContainer);
                        this.jq("body").append(wp.$ele);

                        wp.$ele.wrap('<div style="position:absolute;"></div>');
                        er.container = new MyEleData();
                        er.container.$ele = wp.$ele.parent();
                        er.container.$ele.addClass("maxer-container")
                        ;
                        var $cover = $("<div></div>")
                            .addClass("canvas-cover")
                            .css($.fn.myCanvas.styles.cover)
                            .on("click", function () {
                                self.methods.popMode.call(self, false);
                            });
                        wp.$ele.before($cover);
                        wp.$ele.parent().get(0)[myCanvas.type] = this;
                    }
                }

            }
            ,
            //绘制工具栏
            rendTools: function (isMinMode) {
                myCanvas.Tools.render.call(this, isMinMode);
            }
            ,
            //关闭当前画布，并移除原始元素
            remove: function () {
                this.methods.destory.call(this);
                this._.original.$ele.remove();
            }
            ,
            //退出画布模式，还原原始元素
            destory: function () {
                if (!!this._) {
                    if (!!this._.original.$ele && !!this._.miner.wrapper.$ele) {
                        this._.original.$ele.insertBefore(this._.miner.wrapper.$ele);
                        this._.miner.wrapper.$ele.remove();
                    }
                    if (!!this._.maxer.wrapper.$ele) {
                        this._.maxer.wrapper.$ele.remove();
                    }
                    this._.original.$ele.get(0)[myCanvas.type] = null;
                }
            },
            dispose: function () {
                return this.methods.destory.call(this, arguments);
            },
            //expired:关闭当前画布，并移除原始元素.等同于remove
            close: function () {
                this.methods.apply(this, Array.prototype.slice.call(arguments));
            },
            //显示/退出 最大化模式
            popMode: function (isShow) {
                var max = this._.maxer, min = this._.miner, self = this;
                if (isShow) {
                    this.methods.render.call(this, false);
                    min.wrapper.$ele.hide();
                    //注意，放大模式的wrapper存放的是Container
                    max.wrapper.$ele.parent().show();

                    setTimeout(function () {
                        max.wrapper.$ele.parent().css("z-index", myCanvasMaxZIndex(self.win) + 1);
                        var value = self.methods.getData.call(self);
                        if (!!value)
                            self.methods.setData.call(self, value);
                    });
                }
                else {
                    //注意，放大模式的wrapper存放的是Container
                    max.wrapper.$ele.parent().hide();
                    min.wrapper.$ele.show();
                }
                this.props.isPopup = !!isShow;
            }
        }
        //属性
        , props: {
            //自适应模式：
            //该模式下，height,width无效。
            //使用方法set("width"),set("height")，仅在无法适配大小时有效。
            //
            isAutoSizeMode: true
            ,
            //缩略图高度
            height: 0
            ,
            //缩略图宽度
            width: 0
            ,
            //放大模式宽度
            scaleWidth: "80%"
            ,
            //放大模式高度
            scaleHeight: "80%"
            ,
            //工具栏
            tools: ["pencil", "text", "colors", "width", "eraser", "clear", "undo", "redo", "pop"]
            ,
            //只读
            readonly: false
            ,
            //当前是弹出模式
            isPopup: false
            ,
            //当前画布的图像
            value: null
            ,
            //自动将最大模式放置到最顶层
            isPopupToTop: true
        }
        //事件
        , events: {
            beforeRender: null
            , afterRender: null
            , beforeResize: null
            , afterResize: null
            , beforeRemove: null
            , afterRemove: null
        }
        ,
        //仅供内部使用的数据
        _: {
            hasFitSize: null
            ,
            //缩略图
            miner: new MyAreaData()
            ,
            maxer: new MyAreaData()
            ,
            //原始元素信息
            original: new MyEleData()
            ,
            //工具栏
            tools: new MyEleData()
            ,
            //历史记录
            histories: []
            ,
            //指示鼠标是否在画布内
            isMouseDownInCanvas: false
            ,
            //指示当前工具
            currentTool: null
            ,
            //指示当前文本
            currentText: null
            ,
            //指示当前文本位置
            textLoc: null
            ,
            //指示当前画布文本样式
            currentTextStyle: {}
            ,
            //当前前景色
            currentColor: "#f00"
            ,
            //当前画笔宽度
            currentPenWidth: 16
            ,
            winSize: { height: 0, width: 0 }
        }
        , jq: $
        , win: global
    };

    myCanvas.regHelper = {
        isAllNumber: /^\d+$/
    };

    myCanvas._setScaleSize = function () {
        var er = this._.maxer;
        if (!er.wrapper.$ele)
            return;
        var $container = er.wrapper.$ele
                        , $wrapper = $container.parent()
                        , $min = this._.miner.wrapper.$ele
                        , $minCanvas = this._.miner.canvas.$ele
                        , tools = this._.tools
                        , $tool = tools.$ele
                        , scaleSize = {
                            width: this.props.scaleWidth
                            , height: this.props.scaleHeight
                        }, minSize = {
                            width: $minCanvas.width()
                            , height: $minCanvas.height()
                        }
                        , rate = minSize.width / minSize.height
                        , winSize = this._.winSize
        ;
        initWindowSize(this);
        $wrapper.css($.fn.myCanvas.styles.popContainer);
        $container.css(scaleSize);
        tools.size.height = $tool.height()
        tools.size.width = $tool.width();

        if (/\%/.test(scaleSize.width) || /\%/.test(scaleSize.height)) {
            //百分比模式需要，调整大小
            //step4:获取工具栏的大小
            //step5:将百分比大小，换成实际大小
            if (/\%/.test(scaleSize.width)) {
                scaleSize.width = winSize.width * parseFloat(scaleSize.width) / 100
            };
            if (/\%/.test(scaleSize.height)) {
                scaleSize.height = winSize.height * parseFloat(scaleSize.height) / 100
            };
            //保持比例
            keepWidthVsHeight(rate, scaleSize);
            if (scaleSize.height + tools.size.height > winSize.height) {
                scaleSize.height = winSize.height - tools.size.height - 1;
                $container.height(scaleSize.height);
            }
            var size = {
                height: Math.max(winSize.height, scaleSize.height + tools.size.height)
                , width: scaleSize.width
            };
            //$container.css({
            //    left: (winSize.width - size.width) / 2
            //    , top: (winSize.height - size.height) / 2
            //}).css(size);
        }
        else {
            keepWidthVsHeight(rate, scaleSize);
        }
        er.bg.size = er.canvas.size = scaleSize;
        var cvs = er.canvas.$ele.get(0);
        cvs.height = scaleSize.height;
        cvs.width = scaleSize.width;
        er.bg.$ele.css(scaleSize);
        er.canvas.$ele.css(scaleSize);
        er.wrapper.$ele.css(scaleSize);
        //图片会自动适应居中显示
        makeCenter(this);
    };

    function initWindowSize(self) {
        var $hide = self.jq("body").children(":visible");
        $hide.hide();
        //step2:获取窗体大小
        self._.winSize.height = self.jq(self.win).height();
        self._.winSize.width = self.jq(self.win).width();
        $hide.show();
    }


    function makeCenter(self) {
        var bgSize = self._.maxer.bg.size, winSize = self._.winSize, toolSize = self._.tools.size;
        var left = (winSize.width - bgSize.width) / 2;
        var top = (winSize.height - bgSize.height - toolSize.height) / 2;
        self._.maxer.wrapper.$ele.css({
            left: left
            , top: top
        });
        self._.tools.$ele.css({
            left: left
            , top: top - toolSize.height
            , width: bgSize.width
        });
    };

    function keepWidthVsHeight(rate, scaleSize) {
        var rate1 = scaleSize.width / scaleSize.height;
        if (rate1 > rate) {
            //height变小
            scaleSize.width = rate * scaleSize.height;
        }
        else if (rate1 < rate) {
            //width变小
            scaleSize.height = scaleSize.width / rate;
        }
    }

    //大画布内按下按钮
    myCanvas._KeydownMaxer = function (e) {
        if (e.keyCode == "27" || e.keyCode == 27 || e.keyChar == "Esc") {
            var $t = $(document).find(".myCanvas"), that = $t.data(myCanvas.type);
            if (that.props.isPopup)
                that.methods.popMode.call(that, false);
        }
    };

    //缩略图点击事件
    myCanvas._Click_Miner = function () {
        var $cvs = $(this)
            , that = $cvs.get(0)[myCanvas.type];
        that.methods.popMode.call(that, true);
    };

    //窗体大小变化事件
    myCanvas._SizeChanged = function () {
        var sc = myCanvas._SizeChanged;
        //输出：xxxxxxx   100
        //表明 Date()之间做加减运算返回的是毫秒为单位的数值

        //防止反复计算大小
        if (sc._tick != null) {
            window.clearTimeout(sc._tick);
            sc._tick = setTimeout(function () {
                sc._tick = null;
                $(".miner-wrapper .myCanvas")
                    .myCanvas("resetSize");
            }, 100);
        };
    };

    myCanvas._PropertyChange = function (e, propName, value) {
        var model = this[myCanvas.type];
        switch (propName) {
            case "value":
                {
                    if (value == null || value == "")
                        return;
                    if (!!model._.miner.canvas.$ele && model._.miner.canvas.$ele.length) {
                        model._.miner.canvas.$ele.get(0).src = value;
                    }
                    if (!!model._.maxer.canvas.$ele && model._.maxer.canvas.$ele.length) {
                        var img = new Image();
                        var t = this;
                        img.onload = function () {
                            var cvs = model.methods.getCanvas.call(model)
                         , canvas = cvs.canvas;
                            //保存Size
                            cvs.save();
                            cvs.drawImage(img, 0, 0, canvas.width, canvas.height);
                            //还原Size
                            cvs.restore();
                        }
                        img.src = value;
                    }
                }
                break;
            case "height":
            case "width":
                {
                    model.props.isAutoSizeMode = false;
                    model.methods.resetSize.call(model);
                }
                break;
        }

    };

    myCanvas.lang = {
        tips: {
            noProperty: "没有属性值/No property"
            , del: "确认是否删除本画布/Area you sure to remove this canvas?"
            , canvasHasInited: "画布已存在/The canvas already exists!"
            , clickToPopMode: "点击进入涂鸦模式/Click into Graffiti Mode!"
        }
        , tools: {
            text: "文本工具/Text"
            , pencil: "画笔工具/Pencil"
            , eraser: "橡皮檫/Eraser"
            , undo: "撤销/Undo"
            , redo: "重做/Redo"
            , clear: "清除/Clear"
            , colors: "颜色/Color"
            , width: "画笔粗细/Width"
            , del: "移除/Remove"
            , mouse: "鼠标/Mouse"
            , pop: "缩放/Enlarge or reduce"
        }
        , fonts: {
            bold: "加粗/Bold"
            , italic: "斜体/Italic"
            , fangSong: "仿宋/Arial"
            , kaiti: "楷体/Kai Ti"
            , yaHei: "微软雅黑/Ya Hei"
        }
    };

    myCanvas.styles = {
        cover: {
            width: "100%"
            , "height": "100%"
            , "background": "#000"
            , "opacity": "0.6"
            , "top": 0
            , "left": 0
            , "position": "absolute"
        }, popContainer: {
            width: "100%"
            , "height": "100%"
            , "top": 0
            , "left": 0
            , "position": "absolute"
            , background: "#fff"
        }
    }

    $.fn.myCanvas = myCanvas;

    $(function () {
        var $t = $(".myCanvas");
        $t.myCanvas();
    });

})(jQuery, window);



//工具栏
(function (global) {

    var Tools = {
        //通过工具的元素，获取画布对象
        getCanvasModel: function () {
            var $t = $(this);
            return $t.parentsUntil(".maxer-container")
            .last().parent().find(".my-canvas").get(0)[$.fn.myCanvas.type];
        }
        ,
        //绘制缩略图，缩略图模式不工作
        render: function (isMinMode) {
            var items = this.props.tools, tools = this._.tools
                , $wrapper = isMinMode ? this._.miner.wrapper.$ele : this._.maxer.wrapper.$ele;
            if (isMinMode) {
                //缩略图模式不支持工具栏
            }
            else {
                if (!!this._.original.$ele.attr("readonly")) {
                    items = this.props.tools = ["mouse", "pop"];
                }
                if (tools.$ele == null) {
                    tools.$ele = $("<div></div>")
                    .addClass("canvas-tools");
                    $wrapper.before(tools.$ele);
                    for (var i = 0;i < items.length;i++) {
                        var it = items[i];
                        if (typeof (it) == "string") {
                            var tl = Tools[it];
                            if (tl != null) {
                                Tools._renderTool.call(this, it, tl);
                            }
                            else {
                                global.myCanvasLog(["无法识别的组件", JSON.stringify(it)].join(""));
                            }
                        }
                    }
                    tools.$ele.find(".myCanvas-tools-btn:visible:first").click();
                }
            }
        }
        ,
        //绘制工具图标
        _renderTool: function (name, tl) {
            var $tool = $("<span/>")
                .attr({
                    title: $.fn.myCanvas.lang.tools[tl.title]
                    , "data-tool": name
                    , class: "myCanvas-tools-btn"
                });
            this._.tools.$ele.append($tool);
            $tool.addClass(tl.icon).addClass(["myCanvas-tools", name].join("-"));
            if (tl.exec) {
                $tool.click(tl.exec);
            };
            if (tl.init) {
                tl.init(this, $tool);
            };
        }
        ,
        //激活工具
        active: function () {
            var $t = $(this);
            $expired = $t.parent().find(".actived");
            var model = Tools.getCanvasModel.call(this);
            $expired.each(function () {
                var $tool = $(this)
                    , tool = $tool._canvasTools;
                tool = Tools[tool]
                if (tool != null && tool.cancel != null) {
                    tool.cancel(model);
                };
            });
            $expired.removeClass("actived");
            $t.addClass("actived");
        }
        , showEvent: function (e) {
            if (top.IsDebug) {
                var text = [];
                text.push("type:" + e.type);
                var pos = Tools.getLocation(null, e);
                text.push("x:" + pos.x);
                text.push("x:" + pos.y);
                parent.$("#statusBar").html(text.join(","));
            }
        }
        , getLocation: function (model, e) {
            /// <summary>获取鼠标在画布的坐标</summary>
            //bug:当页面出现滚动条，并滚动时，画笔会上移向下滚动量；向左移动向右滚动量
            if (e.offsetX == undefined) {
                var off = $(e.target).offset();
                if (e.originalEvent.targetTouches[0] == undefined) {
                    return { x: 0, y: 0 };
                };
                return {
                    x: e.originalEvent.targetTouches[0].pageX - off.left
                    , y: e.originalEvent.targetTouches[0].pageY - off.top
                }
            }
            return {
                x: e.offsetX
                , y: e.offsetY
            };
        }
        , saveHistroy: function (model, addon) {
            /// <summary>保存历史记录</summary>
            /// <param name="model" type="Object">画布对象</param>
            /// <param name="addon" type="int">历史记录步进，通常传入1</param>
            var cvs = model.methods.getCanvas.call(model);
            var canvas = cvs.canvas;
            if (canvas.width == 0 || canvas.height == 0) {
                if (Tools.saveHistroy._Tick == undefined)
                    Tools.saveHistroy._Tick = 0;
                if (Tools.saveHistroy._Tick > 3000) {
                    return global.myCanvasLog("无法加载画布尺寸！");
                }
                return setTimeout(function () {
                    Tools.saveHistroy._Tick++;
                    Tools.saveHistroy(model, addon);
                }, 10);
            };
            var dd = cvs.getImageData(0, 0, canvas.width, canvas.height);
            var value = canvas.toDataURL("image/png");
            model.methods.setData.call(model, value);
            //不传入步进，则直接清空历史记录
            if (addon === null) {
                addon = -model._.tools.historyIndex;
            }
            model._.tools.historyIndex = model._.tools.historyIndex + addon;
            model._.histories[model._.tools.historyIndex] = dd;
            model._.original.$ele.trigger("change");
        }
        , pencil: {
            title: "pencil"
            , icon: "fa fa-pencil"
            , exec: function (e) {
                var $t = $(this),
                    model = Tools.getCanvasModel.call(this);
                if (model.props.readonly) {
                    e.preventDefault();
                    return false;
                };
                Tools.active.call(this);
                model._.currentTool = "pen";
                function onMouseDown(e) {
                    Tools.showEvent.apply(this, arguments);
                    var $t = $(this), model = Tools.getCanvasModel.call(this);
                    if (model._.currentTool == "pen") {
                        model._.isMouseDownInCanvas = true;
                        var cvs = model.methods.getCanvas.call(model);
                        model._pencilLoc = { x: cvs.canvas.offsetLeft, y: cvs.canvas.offsetTop };
                        var pos = Tools.getLocation(model, e, model._pencilLoc);
                        cvs.beginPath();
                        cvs.moveTo(pos.x, pos.y);
                        cvs.strokeStyle = model._.currentColor;
                        cvs.shadowColor = model._.currentColor;
                        cvs.lineWidth = model._.currentPenWidth;

                        e.preventDefault();
                        return false;
                    }
                }
                function onMouseMove(e) {
                    Tools.showEvent.apply(this, arguments);
                    var $t = $(this), model = Tools.getCanvasModel.call(this)
                    , canvas = model._.maxer.canvas.$ele[0];
                    var cvs = model.methods.getCanvas.call(model);
                    if (model._.currentTool == "pen" && model._.isMouseDownInCanvas) {
                        var loc = Tools.getLocation(model, e, model._pencilLoc);
                        cvs.lineTo(loc.x, loc.y);
                        cvs.stroke();
                        global.myCanvasLog(global.myCanvasFormat("pencil line {0}", JSON.stringify(loc)));
                    }
                }
                function onMouseUp() {
                    Tools.showEvent.apply(this, arguments);
                    var $t = $(this), model = Tools.getCanvasModel.call(this);
                    if (model._.currentTool == "pen" && model._.isMouseDownInCanvas) {
                        var cvs = model.methods.getCanvas.call(model);
                        cvs.closePath();
                        Tools.saveHistroy(model, 1);
                    }
                    model._.isMouseDownInCanvas = false;
                }
                model._.maxer.canvas.$ele
                    .unbind("mousedown")
                    .unbind("mouseup")
                    .unbind("mousemove")
                    .unbind("touchstart")
                    .unbind("touchend")
                    .unbind("touchmove")
                    .bind("mousedown", onMouseDown)
                    .bind("mouseup", onMouseUp)
                    .bind("mousemove", onMouseMove)
                    .bind("touchstart", onMouseDown)
                    .bind("touchend", onMouseUp)
                    .bind("touchmove", onMouseMove)
                ;

                e.preventDefault();
                return false;
            }
        }
        , text: {
            title: "text"
            , icon: "fa fa-font"
            , exec: function (e) {
                var $t = $(this),
                    model = Tools.getCanvasModel.call(this);
                if (model.props.readonly) {
                    e.preventDefault();
                    return false;
                };
                Tools.active.call(this);
                model._.currentTool = "text";
                model._.maxer.canvas.$ele
                    .unbind("click")
                    .bind("click", Tools.text.click_Cancas);
                e.preventDefault();
                return false;
            }
            , cancel: function (model) {
                if (model._.textTool) {
                    model._.textTool.find(".canvas-text-input").val("");
                    model._.textTool.hide();
                };
                Tools.saveHistroy(model, 1);
            }
            , click_Cancas: function (e) {
                var $t = $(this), model = Tools.getCanvasModel.call(this);
                if (model._.currentTool == "text") {
                    //当前已经是文本工具
                    if (e.fromElement == null || e.fromElement === e.toElement) {
                        //，并且，点击在Canvas上
                        var text = Tools.text.getInputedText(model);
                        if (text == null) {
                            Tools.text.showInputTool(e, $t, model);
                        }
                        else if (text.trim() == "") {
                            Tools.text.cancel(model);
                            Tools.text.showInputTool(e, $t, model);
                        }
                        else {
                            Tools.text.cancel(model);
                        }
                    }
                    else {
                        //点击在文本工具内
                    }
                }
                else {
                    //当前不是文本工具
                    if (model._.currentText) {
                        Tools.text.cancel(model);
                    }
                }
            }
            , keyUp_Text: function (e) {
                var model = Tools.getCanvasModel.call(this)
                , $t = model._.maxer.canvas.$ele
                ;
                return Tools.text.startWrite(e, $t, model, false);
            }
            , startWrite: function (e, $t, model) {
                var txt = Tools.text.getInputedText(model);
                var canvasElement = model._.maxer.canvas.$ele.get(0);
                var font = global.myCanvasFormat("{0} normal {1} {2} {3}"
                       , model._.currentTextStyle["font-style"]
                        , model._.currentTextStyle["font-weight"]
                        , model._.currentTextStyle["font-size"]
                        , model._.currentTextStyle["font-family"]
                    );
                if (txt == null || txt == "") return;
                var height = Tools.text.getFontHeight(model);
                //清理掉上次写入的文本
                if (model._.tools.historyIndex > 0) {
                    var img = model._.histories[model._.tools.historyIndex];
                    if (img)
                        model.methods.getCanvas.call(model).putImageData(img, 0, 0);
                };
                Tools.text.write(canvasElement, height, txt, font, model._.currentColor
                        , model._.textLoc.x, model._.textLoc.y);
            }
            , write: function (cns, lh, text, font, color, left, top) {
                /// <summary>写字到Canvas上去</summary>
                /// <param name="cns" type="Element">Canvas元素</param>
                /// <param name="lh" type="int">字体行高</param>
                /// <param name="text" type="String">写入文本</param>
                /// <param name="font" type="String">字体信息</param>
                /// <param name="color" type="String">前景色</param>
                /// <param name="left" type="float">绘制的字离左边框的距离</param>
                /// <param name="top" type="float">绘制的字离顶部的距离</param>
                var ctx = cns.getContext("2d");
                var lineheight = lh;
                var text = text;

                ctx.width = cns.width;
                ctx.height = cns.height;

                //ctx.clearRect(0, 0, ctx.width, ctx.height);
                ctx.font = font;
                ctx.fillStyle = color;
                var lines = text.split('\n');
                for (var i = 0;i < lines.length;i++) {
                    var tl = lines[i];
                    ctx.fillText(tl, left, top + (i + 0.46) * lineheight);
                }
            }
            , getFontHeight: function (model) {
                /// <summary>获取字体行高</summary>
                var $ip = model._.original.$ele.parent().find(".canvas-text-input")
                    , lh = $ip.css("line-height")
                    , fs = $ip.css("font-size")
                    , lineHeight = parseFloat(lh)
                    , fontSize = parseFloat(fs);
                if (isNaN(lineHeight)) {
                    //未设置行高的情况
                    if (model.$span == null) {
                        model.$span = $("<span></span>");
                        model.$span.css({
                            "padding": "0"
                            , "margin": "0"
                            , "line-height": "normal"
                        });
                        model.$span.html("123456789 English //简体中文");
                        $("body").append(model.$span);
                    };
                    model.$span.show();
                    model.$span.css({
                        "font-size": fs
                        , "font-family": $ip.css("font-family")
                        , "font-style": $ip.css("font-style")
                        , "font-weight": $ip.css("font-weight")
                    });
                    lineHeight = model.$span.height();
                };
                //最小要有10px的高度
                lineHeight = Math.max(10, lineHeight);
                global.myCanvasLog(["lineHeight:", lineHeight].join(""));
                return lineHeight;
            }
            , getInputedText: function (model) {
                var $box = Tools.text.getInputTextBox(model);
                if (!!$box && $box.length > 0)
                    return $box.val();
                return null;
            }
            , template: '<div class="text-tool">\
<input type="checkbox" value="bold" id="font-weight"/>\
<label for="font-weight">{0}</label>\
<input type="checkbox" value="italic" id="font-style"/>\
<label for="font-style">{1}</label>\
<select id="font-size">\
<option>9px</option><option >12px</option><option selected="selected">15px</option><option>21px</option><option>30px</option><option>50px</option>\
</select>\
<select id="font-family">\
<option value="FangSong">{2}</option><option value="KaiTi">{3}</option><option selected="selected" value="Microsoft YaHei">{4}</option><option value="Arial">Arial</option>\
</select>\
<textarea row=1 cols=20 class="canvas-text-input"></textarea>\
</div>'
            , showInputTool: function (e, $t, model) {
                top.model = model;
                if (model._.tools.historyIndex <= 0) {
                    Tools.saveHistroy(model, 1);
                };
                if (!model._.textTool) {
                    var template = Tools.text.template;
                    template = global.myCanvasFormat(template
                        , $.fn.myCanvas.lang.fonts.bold, $.fn.myCanvas.lang.fonts.italic, $.fn.myCanvas.lang.fonts.fangSong
                        , $.fn.myCanvas.lang.fonts.kaiti, $.fn.myCanvas.lang.fonts.yaHei);
                    model._.textTool = $(template)
                        .addClass("canvas-text-tools");
                    model._.tools.$ele.append(model._.textTool);
                    Tools.text.bindEvents(model);
                }
                model._.textTool.show();
                model._.textLoc = Tools.getLocation(model, e, model._.textLoc);
                global.myCanvasLog(JSON.stringify(model._.textLoc));

                Tools.text.getInputTextBox(model).focus();

                e.preventDefault();
                return false;
            }
            , bindEvents: function (model) {
                model._.textTool.find("input,select")
                    .change(function (e) {
                        var $t = $(this)
                            , id = $t.attr("id")
                            , val = null;
                        var model = Tools.getCanvasModel.call(this)
                        ;
                        if ($t.is("input")) {
                            if ($t.prop("checked")) {
                                val = $t.val();
                            }
                            else {
                                val = "normal";
                            }
                        }
                        else {
                            val = $t.find(":selected");
                            if (val.attr("value")) {
                                val = val.attr("value");
                            }
                            else {
                                val = val.text().trim();
                            }
                        }
                        model._.currentTextStyle[id] = val;
                        Tools.text.startWrite(e, $t, model);
                    }).change();

                Tools.text.getInputTextBox(model)
                    .on("keyup", Tools.text.keyUp_Text)
            }
            , getInputTextBox: function (model) {
                if (!!model._.textTool)
                    return model._.textTool.find(".canvas-text-input");
                return null;
            }
        }
        , eraser: {
            title: "eraser"
            , icon: "fa fa-eraser"
            , exec: function () {
                var $t = $(this),
                    model = Tools.getCanvasModel.call(this);
                if (model.props.readonly) {
                    e.preventDefault();
                    return false;
                };
                Tools.active.call(this);
                model._.currentTool = "eraser";
                function onMouseDown(e) {
                    var $t = $(this),
                     model = Tools.getCanvasModel.call(this);
                    if (model._.currentTool == "eraser") {
                        model._.isMouseDownInCanvas = true;
                        var pos = Tools.getLocation(model, e, { x: 0, y: 0 });
                        var cvs = model.methods.getCanvas.call(model);
                        var half = model._.currentPenWidth / 2;
                        half = Math.ceil(half);
                        cvs.clearRect(pos.x - half, pos.y - half, 2 * half, 2 * half);
                        e.preventDefault();
                        return false;
                    }
                }

                function onMouseMove(e) {
                    var $t = $(this),
                     model = Tools.getCanvasModel.call(this);
                    if (model._.currentTool == "eraser" && model._.isMouseDownInCanvas) {
                        var pos = Tools.getLocation(model, e, { x: 0, y: 0 });
                        var cvs = model.methods.getCanvas.call(model);
                        var width = model._.currentPenWidth * 4;//粗一点！
                        var half = width / 2;
                        cvs.clearRect(pos.x - half, pos.y - half, width, width);
                    }
                }


                function onMouseUp(e) {
                    var $t = $(this),
                     model = Tools.getCanvasModel.call(this);
                    if (model._.currentTool == "eraser" && model._.isMouseDownInCanvas) {
                        Tools.saveHistroy(model, 1);
                    }
                    model._.isMouseDownInCanvas = false;
                }

                model._.maxer.canvas.$ele
                    .unbind("mousedown")
                    .unbind("mouseup")
                    .unbind("mousemove")
                    .unbind("touchstart")
                    .unbind("touchend")
                    .unbind("touchmove")
                    .bind("mousedown", onMouseDown)
                    .bind("mouseup", onMouseUp)
                    .bind("mousemove", onMouseMove)
                    .bind("touchstart", onMouseDown)
                    .bind("touchend", onMouseUp)
                    .bind("touchmove", onMouseMove)
                ;
            }
        }
        , undo: {
            title: "undo"
            , icon: "fa fa-undo"
            , exec: function (e) {
                var $t = $(this)
                    , model = Tools.getCanvasModel.call(this);
                if (model.props.readonly) {
                    e.preventDefault();
                    return false;
                };
                var canvas = model._.maxer.canvas.$ele[0];
                var cvs = model.methods.getCanvas.call(model);
                if (model._.tools.historyIndex > 0)
                    model._.tools.historyIndex--;
                var img = model._.histories[model._.tools.historyIndex];
                if (img)
                    cvs.putImageData(img, 0, 0);
                e.preventDefault();
                return false;
            }
            , init: function (model, $ele) {
                model._.tools.historyIndex = -1;
                Tools.saveHistroy(model, 1);
            }
        }
        , redo: {
            title: "redo"
            , icon: "fa fa-repeat"
            , exec: function (e) {
                var $t = $(this)
                    , model = Tools.getCanvasModel.call(this)
                if (model.props.readonly) {
                    e.preventDefault();
                    return false;
                };
                var canvas = model._.maxer.canvas.$ele[0];
                var cvs = model.methods.getCanvas.call(model);
                if (model._.tools.historyIndex + 1 < model._.histories.length)
                    model._.tools.historyIndex++;
                var img = model._.histories[model._.tools.historyIndex];
                if (img)
                    cvs.putImageData(img, 0, 0);
                e.preventDefault();
                return false;
            }
        }
        , clear: {
            title: "clear"
            , icon: "fa fa-eraser"
            , exec: function (e) {
                var $t = $(this)
                    , model = Tools.getCanvasModel.call(this);
                var canvas = model._.maxer.canvas.$ele[0];
                var cvs = model.methods.getCanvas.call(model);
                cvs.clearRect(0, 0, canvas.width, canvas.height);
                var dd = cvs.getImageData(0, 0, cvs.canvas.width, cvs.canvas.height);
                Tools.saveHistroy(model, 1);
                e.preventDefault();
                return false;
            }
            , init: function (self, $tool) {
                $tool.css("color", "#f63");
            }
        }
        , colors: {
            title: "colors"
            , icon: "fa fa-spinner"
            , options: ["#000", "#f00", "#0f0", "#00f", "#ff0", "#f0f", "#0ff", "#fff"]
            , exec: function (e) {
                var $t = $(this)
                , $menu = this["menu"]
                , colors = Tools.colors.options;
                $t.parent().find(".canvas-tools-menu").hide();
                if ($menu == null) {
                    this["menu"] = $menu = $("<ul>")
                    .addClass("canvas-tools-menu")
                    .addClass("canvas-tools-colors")
                    for (var i = 0;i < colors.length;i++) {
                        var c = colors[i];
                        var $li = $("<li/>");
                        $li.addClass("fa fa-circle")
                        .css({
                            "color": c
                        })
                        .attr("data-color", c)
                        .data("control", this)
                        .click(function () {
                            var $t = $(this)
                            , model = Tools.getCanvasModel.call(this);
                            model._.currentColor = $t.data("color");
                            var ctr = $t.data("control")
                            $(ctr).css("color", model._.currentColor);
                            $t.parent().hide();
                        });
                        $menu.append($li);
                    }
                    $t.parent().append($menu);
                }
                var pos = $t.position();
                Tools.active.call(this);
                $menu.css({
                    left: pos.left
                    , top: pos.top + $t.outerHeight(true)
                }).show();

                e.preventDefault();
                return false;
            }
            , init: function (model, $ele) {
                if (model._.tools.color == null)
                    model._.tools.color = "#f00";
                $ele.css("color", model._.tools.color);
            }
            , cancel: function () {
                $(".canvas-tools-menu:visible").hide();
            }
        }
        , width: {
            title: "width"
            , options: ["1px", "2px", "4px", "8px", "16px", "32px", "64px"]
            , icon: "fa fa-circle"
            , exec: function (e) {
                var $t = $(this)
               , $menu = this["menu"]
               , widths = Tools.width.options;
                $t.parent().find(".canvas-tools-menu").hide();
                if ($menu == null) {
                    this["menu"] = $menu = $("<ul>")
                    .addClass("canvas-tools-menu")
                    .addClass("canvas-tools-width")
                    for (var i = 0;i < widths.length;i++) {
                        var w = widths[i], wi = parseInt(w);
                        var height = Math.max(25, wi).toString() + "px";
                        var $icon = $("<a></a>")
                            .addClass("fl")
                            .addClass("icon")
                        .css({
                            width: w
                            , height: w
                            , "border-radius": w
                            , "margin-top": wi > 12 ? "auto" : ((12 - wi).toString() + "px")
                        });
                        var $lable = $("<a></a>")
                        .addClass("fr")
                        .html(w);
                        var $li = $("<li></li>");
                        $li
                        .append($lable)
                        .append($icon)
                        .addClass(["height-", w].join(""))
                        .css({
                            "line-height": height
                            , "height": height
                        })
                        $li
                        .click(function () {
                            var $t = $(this)
                            , model = Tools.getCanvasModel.call(this);
                            model._.currentPenWidth = parseInt($t.text());
                            $t.parent().hide();
                        });
                        $menu.append($li);
                    }
                    $t.parent().append($menu);
                }
                var pos = $t.position();
                Tools.active.call(this);
                $menu.css({
                    left: pos.left
                    , top: $t.outerHeight(true)
                }).show();
                e.preventDefault();
                return false;
            }, cancel: function () {
                $(".canvas-tools-menu:visible").hide();
            }
        }
        , del: {
            title: "del"
            , icon: "fa fa-remove"
            , exec: function (e) {
                var $t = $(this)
                    , model = Tools.getCanvasModel.call(this);
                if (model.props.readonly) {
                    e.preventDefault();
                    return false;
                };
                var rs = model._.original.$ele.triggerHandler("beforedelete");
                if (rs !== false) {
                    if (rs === "beforedelete") {
                        model._.original.$ele.on("confirmdelete", function () {
                            model._.original.$ele
                                .off("confirmdelete")
                            .off("canceldelete");
                            model._.original.$ele.trigger("delete");
                            $container.remove();
                        }).on("canceldelete", function () {
                            model._.original.$ele
                                .off("confirmdelete")
                            .off("canceldelete");
                        });
                    } else {
                        model._.original.$ele.trigger("delete");
                        $container.remove();
                        $(".pop-canvas").hide();
                    }
                };
                Tools.saveHistroy(model, 1);
                e.preventDefault();
                return false;
            }
            , init: function (self, $tool) {
                $tool.css("color", "#f63");
            }
        }
        , mouse: {
            title: "mouse"
            , icon: "fa fa-mouse-pointer"
            , exec: function (e) {
                var $t = $(this)
                    , $container = $t.parentsUntil(".canvas-container")
                       .last().parent()
                    , model = Tools.getCanvasModel.call(this);
                Tools.active.call(this);
                model._.currentTool = "mouse";
            }
        }
        , pop: {
            title: "pop"
            , icon: "fa fa-remove"
            , exec: function (e) {
                var $t = $(this)
                    , $container = $t.parentsUntil(".canvas-container")
                       .last().parent()
                    , model = Tools.getCanvasModel.call(this);

                var $icon = model._.maxer.wrapper.$ele.find(".pop");
                //$icon.removeClass("fa-search-plus")
                //.removeClass("fa-search-minus");
                if (!!model.props.isPopup) {
                    //$icon.addClass("fa-search-plus");
                    model.methods.popMode.call(model, false);
                }
                else {
                    //$icon.addClass("fa-search-minus");
                    model.methods.popMode.call(model, true);
                }

            }
            , init: function (self, $tool) {
                $tool.css("color", "#f63");
            }
        }
    };


    $.fn.myCanvas.Tools = Tools;


})(window);
